const gulp = require('gulp')
// 浏览器同步测试工具
const browserSync = require('browser-sync').create()
// 同步执行任务
const runSequence = require('run-sequence')
// gulp-sourcemap用于调试
// 将Browserify的bundle()的输出转换为Gulp可用的[vinyl][]（一种虚拟文件格式）流   for gulp
const source = require('vinyl-source-stream')
// 将vinyl流转化为buffered vinyl文件（gulp-sourcemaps及大部分Gulp插件都需要这种格式）  for gulp-sourcemaps
const buffer = require('vinyl-buffer')
// gulp-load-plugins插件化
const plugins = require('gulp-load-plugins')()
// 日志记录
const log = plugins.util.log
// 错误提示颜色
const red = plugins.util.colors.red
// 成功提示颜色
const green = plugins.util.colors.green
// 提示文字颜色
const blue = plugins.util.colors.blue
// event-stream事件流
const es = require('event-stream')
// del删除文件
const del = require('del')

const config = require('./build/config')
const bundleTasks = require('./build/browserify')

// [启动] browserSync
gulp.task('start:browserSync', () => browserSync.init({
	// proxy: '10.2.126.147',
	notify: true,
	server: {
		baseDir: './',
		index: 'html/index.html'
	}
}));

// 刷新浏览器
gulp.task('reload:browser', cb => {
	browserSync.reload();
	cb();
});

/**
 * js任务流，具体包括：
 * 模块打包 --> 路径修正(重命名) --> babel --> 打开sourcemaps调试 --> md5(production状态) --> 产出
 * @param {Object} bundle 各入口文件的browserify对象
 * @param {string} filename 入口文件名
 * @return {stream} stream 对象
 */
const jsTask = ({ bundle, filename }) => (
	bundle.bundle(err => {
		if (err) {
			browserSync.notify(`[Browserify Error] ${err.message}`, 10000)
			log(red('[Browserify Error]'), red(err.message))
		}
	})
	.pipe(plugins.plumber(err => {
		log(red(`[${err.plugin}]`), red(err.message))
	}))
	.pipe(source(filename))
	.pipe(buffer())
	.pipe(process.env.NODE_ENV === 'development' ? plugins.sourcemaps.init({loadMaps: true}) : plugins.util.noop())
	.pipe(plugins.babel({
		presets: ['env']
	}))
	.pipe(process.env.NODE_ENV === 'production' ? plugins.uglify() : plugins.util.noop())
	.pipe(process.env.NODE_ENV === 'development' ? plugins.sourcemaps.write(".") : plugins.util.noop())
	.pipe(plugins.rename({
		dirname: ''
	}))
	.pipe(gulp.dest(config.DIST_JS_PATH))
)

// [发布] js代码，其中会进行js相关工作流程
gulp.task("dist:js", cb => {
	let streams = bundleTasks.map(jsTask)
	return es.merge(streams)
});

// [发布] css代码
gulp.task("dist:css", () => {
	gulp.src(`${config.SRC_CSS_PATH}/**/*.less`)
		.pipe(plugins.rename({
			dirname: ''
		}))
		.pipe(plugins.less())
		.pipe(process.env.NODE_ENV === 'production' ? plugins.minifyCss() : plugins.util.noop())
		.pipe(gulp.dest(config.DIST_CSS_PATH));
});

/**
 * 监听各个browserify对象的update事件
 * 在模块更新时按需打包
 * @param {Object} bundle 各入口文件的browserify对象
 * @param {string} filename 入口文件名
 */
const addBundleTaskListeners = ({ bundle, filename }) => {
	bundle.on('update', () => {
		log(blue('[Browserify Update]'), filename);
		let sm = jsTask({ bundle, filename });
		// 打包完成后刷新浏览器（错误不刷新，保留notify）
		sm.on('end', () => runSequence('reload:browser'));
	})
}

// [监听] 为所有入口文件对应的browserify对象添加update监听
gulp.task('watch:js', () => {
	bundleTasks.forEach(item => {
		addBundleTaskListeners(item)
	})
})

// [监听] 更新CSS
gulp.task('watch:css', cb => {
	gulp.watch(['!**/gulpfile.js', 'src/**/*.css', 'src/**/*.less'], () => {
    runSequence(
      'del:css',
      'dist:css',
      'reload:browser'
    );
  });
  cb()
})

// [监听]html文件变化
gulp.task('watch:html', () => {
  gulp.watch('html/**/*.html', ['reload:browser']);
});

// 发布
// build任务，进行项目资源发布
gulp.task('build', cb => {
  runSequence(
    ['del:css', 'del:js'],
    'dist:css',
    'dist:js',
    cb
  );
});

// 开发模式
// 执行发布，并进行监听
gulp.task('default', cb => {
	runSequence(
		'build',
		'start:browserSync',
		['watch:js', 'watch:html', 'watch:css'],
		cb
	)
});

// 发布模式
// 构建资源发布，并退出gulp进程
gulp.task('release', cb => {
	runSequence(
		'build',
		() => {
			cb();
			process.nextTick(process.exit);
		}
	)
})

// [删除] 发布目录下的js文件
gulp.task('del:js', () => del.sync([`${config.DIST_JS_PATH}/*`]));

// [删除]发布目录下的css文件
gulp.task('del:css', () => del.sync([`${config.DIST_CSS_PATH}/*`]));

// [删除]发布目录额下的html文件
// gulp.task('del:html', () => del.sync([`${config.DIST_HTML_PATH}/*`]));